package be.novelfaces.showcase;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.faces.FacesException;
import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

/**
 * Copied this class from the richfaces showcase org.richfaces.demo.components.sh.SyntaxHighlighter
 *
 */
@FacesComponent(value = "syntaxHighlighter")
@ResourceDependencies({
		@ResourceDependency(library = "showcase", name = "js/shCore.js"),
		@ResourceDependency(library = "primefaces", name = "jquery.js"),
		@ResourceDependency(library = "showcase", name = "css/shCore.css"),
		@ResourceDependency(library = "showcase", name = "css/shThemeDefault.css"),
		@ResourceDependency(library = "showcase", name = "js/shBrushJScript.js"),
		@ResourceDependency(library = "showcase", name = "js/shBrushJava.js"),
		@ResourceDependency(library = "showcase", name = "js/shBrushXml.js"),
		@ResourceDependency(library = "showcase", name = "js/shBrushCss.js"),
		@ResourceDependency(library = "showcase", name = "js/shBrushPlain.js") })
public class SyntaxHighlighter extends UIComponentBase {
	private static final String COMPONENT_FAMILY = "be.novelfaces.SyntaxHighlighter";
	private static final String DEFAULT_SOURCE_TYPE = "xhtml";

	enum propertyKeys {
		sourceType, src, style, styleClass
	};

	@Override
	public String getFamily() {
		return COMPONENT_FAMILY;
	}

	private void renderStream(FacesContext context, InputStream stream)
			throws IOException {
		ResponseWriter writer = context.getResponseWriter();
		InputStreamReader in = new InputStreamReader(stream);
		char[] temp = new char[1024];
		try {
			int bytes;
			while ((bytes = in.read(temp)) > 0) {
				writer.writeText(temp, 0, bytes);
			}
		} catch (IOException e) {
			throw new FacesException(e);
		} finally {
			in.close();
		}
	}

	private void renderLabel(FacesContext context, String label)
			throws IOException {
		ResponseWriter writer = context.getResponseWriter();
		writer.writeText(label.toCharArray(), 0, label.length());
	}

	private void renderContent(FacesContext context) throws IOException {
		ExternalContext ec = FacesContext.getCurrentInstance()
				.getExternalContext();
		String src = getSrc();
		if (src != null) {
			InputStream stream = ec.getResourceAsStream(src);
			if (stream != null) {
				renderStream(context, stream);
			} else {
				renderLabel(context, "resource for highlight not found");
			}
		} else {
			renderLabel(context, "src may not be null");
		}
	}

	@Override
	public void encodeEnd(FacesContext context) throws IOException {
		ResponseWriter writer = context.getResponseWriter();
		writer.startElement("div", null);
		writer.writeAttribute("id", this.getClientId(context), null);
		writer.writeAttribute("class", this.getStyleClass(), null);
		writer.writeAttribute("style", this.getStyle(), null);
		writer.startElement("pre", null);
		writer.writeAttribute("class", new StringBuffer().append("brush: ")
				.append(this.getSourceType()), null);
		renderContent(context);
		writer.endElement("pre");
		writer.startElement("script", null);
		writer.write("var brs = $('#"
				+ this.getClientId(context).replaceAll(":", "\\\\\\\\:")
				+ "').find('br');");
		writer.write("brs.length && brs.replaceWith('\\n');");
		writer.write("SyntaxHighlighter.all();");
		writer.endElement("script");
		writer.endElement("div");
	}

	public String getSourceType() {
		return (String) getStateHelper().eval(propertyKeys.sourceType,
				DEFAULT_SOURCE_TYPE);
	}

	public void setSourceType(String sourceType) {
		getStateHelper().put(propertyKeys.sourceType, sourceType);
	}

	public String getSrc() {
		return (String) getStateHelper().eval(propertyKeys.src);
	}

	public void setSrc(String src) {
		getStateHelper().put(propertyKeys.src, src);
	}

	public String getStyle() {
		return (String) getStateHelper().eval(propertyKeys.style);
	}

	public void setStyle(String style) {
		getStateHelper().put(propertyKeys.style, style);
	}

	public String getStyleClass() {
		return (String) getStateHelper().eval(propertyKeys.styleClass);
	}

	public void setStyleClass(String styleClass) {
		getStateHelper().put(propertyKeys.styleClass, styleClass);
	}
}
